"""
例2: 栈

1. **定义与特性**

    栈(Stack)是一种特殊的线性数据结构，它只允许在一端（称为“栈顶”）进行数据的插入和删除操作。这种特性也使得栈具有以下几个独特的特点：

    - **后进先出 (LIFO)原则**：栈是遵循后进先出的原则，即最后压入栈的元素，将会首先被弹出。这是栈最基本的特性。
    - **栈顶操作**：栈只允许在一端（栈顶）添加元素（也称为“压入”或“入栈”）或者移除元素（也称为“弹出”或“出栈”）。其他位置的元素无法直接访问，只能通过连续的弹出操作来访问。
    - **空栈和栈的大小**：当一个栈没有任何元素时，我们称其为“空栈”。我们也可以通过计数元素来确定栈的大小或者长度。
    
2. **应用**

    栈在计算机科学和程序设计中有广泛的应用，例如函数调用、算术表达式求值、符号匹配、页面历史记录等。特别是在需要后退操作或者历史记录的场景下，栈的应用尤为突出。

3. **主要操作**

    栈的主要操作包括：

    - **Push**：将一个元素压入栈顶。
    - **Pop**：将栈顶元素弹出，并返回该元素。
    - **Peek/Top**：查看栈顶元素，但不弹出该元素。
    - **IsEmpty**：检查栈是否为空。
    - **Size**：获取栈的元素个数。

    这些操作共同构成了栈的基本操作集合，对于实现各类算法和应用程序有着至关重要的作用。

以上就是关于“栈”的全面详细的结构化描述，通过了解这些，你将会对栈有一个更深入的理解，并可以更好地在实践中使用栈。

"""

class Stack:
    def __init__(self):
        self.stack = []

    def push(self, value):
        self.stack.append(value)

    def pop(self):
        if not self.is_empty():
            return self.stack.pop()
        else:
            return None

    def peek(self):
        if not self.is_empty():
            return self.stack[-1]
        else:
            return None

    def is_empty(self):
        return len(self.stack) == 0

    def size(self):
        return len(self.stack)

    def display(self):
        max_len = max([len(str(e)) for e in self.stack] + [len("*Bottom*"), len("*Top*")])
        print(f"+--{'*Bottom*':-^{max_len}}--+")
        for element in reversed(self.stack):
            print(f"|  {element: ^{max_len}}  |")
        print(f"+--{'*Top*':-^{max_len}}--+")

if __name__ == '__main__':
    stack = Stack()
    stack.push('v1')
    stack.push('value2')
    stack.peek()
    stack.push('v3')
    stack.push('vvvvvvvvvvvvv4')
    stack.display()
    """output
    +-----*Bottom*-----+
    |  vvvvvvvvvvvvv4  |
    |        v3        |
    |      value2      |
    |        v1        |
    +------*Top*-------+
    """
    stack.pop()
    print(stack.size()) # output: 3
    stack.display()
    """output
    +--*Bottom*--+
    |     v3     |
    |   value2   |
    |     v1     |
    +---*Top*----+
    """
